/*
* Created by boil on 2023/10/22.
*/

#ifndef RENDU_SOCKET_H
#define RENDU_SOCKET_H

#include "define.h"
#include "i_socket.h"
#include "endpoint/ip_end_point.h"
#include "exception/socket_exception.h"
#include "socket_num.h"
#include "socket_fd.h"
#include "net/event_loop.h"
#include "time/timer.h"
#include "time/time_ticker.h"
#include "thread/mutex_wrapper.h"
#include "utils/bytes_speed.h"
#include "buffer_list.h"

RD_NAMESPACE_BEGIN

#define TraceP(ptr) LOG_TRACE << ptr->GetIdentifier() << "(" << ptr->GetRemoteIp() << ":" << ptr->GetRemotePort() << ") "
#define DebugP(ptr) LOG_DEBUG << ptr->GetIdentifier() << "(" << ptr->GetRemoteIp() << ":" << ptr->GetRemotePort() << ") "
#define InfoP(ptr) LOG_INFO << ptr->GetIdentifier() << "(" << ptr->GetRemoteIp() << ":" << ptr->GetRemotePort() << ") "
#define WarnP(ptr) LOG_WARN << ptr->GetIdentifier() << "(" << ptr->GetRemoteIp() << ":" << ptr->GetRemotePort() << ") "
#define ErrorP(ptr) LOG_ERROR << ptr->GetIdentifier() << "(" << ptr->GetRemoteIp() << ":" << ptr->GetRemotePort() << ") "

  class Socket : public std::enable_shared_from_this<Socket>, public ISocket {
  public:
    Socket(const EventLoop::Ptr &poller = nullptr, bool enable_mutex = true);

    Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);

    ~Socket() override;

  public:
    IPEndPoint *GetEndPoint() override;

    void Bind(IPEndPoint *endPoint) override;

    void Close() override;

    void Listen(int backlog) override;

    ISocket *Accept() override;

    void Connect(const char *remote_host, uint16_t remote_port) override;

    string GetLocalIp() override;

    uint16_t GetLocalPort() override;

    string GetRemoteIp() override;

    uint16_t GetRemotePort() override;

    string GetIdentifier() const override;

  public:
    using Ptr = std::shared_ptr<Socket>;
    //接收数据回调
    using onReadCB = std::function<void(const ABuffer::Ptr &buf, struct sockaddr *addr, int addr_len)>;
    //发生错误回调
    using onErrCB = std::function<void(const SockException &err)>;
    //tcp监听接收到连接请求
    using onAcceptCB = std::function<void(Socket::Ptr &sock, std::shared_ptr<void> &complete)>;
    //socket发送缓存清空事件，返回true代表下次继续监听该事件，否则停止
    using onFlush = std::function<bool()>;
    //在接收到连接请求前，拦截Socket默认生成方式
    using onCreateSocket = std::function<Ptr(const EventLoop::Ptr &poller)>;
    //发送buffer成功与否回调
    using onSendResult = BufferList::SendResult;

  public:
    /**
     * 构造socket对象，尚未有实质操作
     * @param poller 绑定的poller线程
     * @param enable_mutex 是否启用互斥锁(接口是否线程安全)
    */
    static Ptr CreateSocket(const EventLoop::Ptr &poller = nullptr, bool enable_mutex = true);

  public:
    /**
     * 创建tcp监听服务器
     * @param port 监听端口，0则随机
     * @param local_ip 监听的网卡ip
     * @param backlog tcp最大积压数
     * @return 是否成功
     */
    bool listen(uint16_t port, const std::string &local_ip = "::", int backlog = 1024);

    /**
    * 创建tcp客户端并异步连接服务器
    * @param url 目标服务器ip或域名
    * @param port 目标服务器端口
    * @param con_cb 结果回调
    * @param timeout_sec 超时时间
    * @param local_ip 绑定本地网卡ip
    * @param local_port 绑定本地网卡端口号
    */
    void connect(const std::string &url, uint16_t port, const onErrCB &con_cb, float timeout_sec = 5,
                 const std::string &local_ip = "::", uint16_t local_port = 0);

    /**
     * 从另外一个Socket克隆
     * 目的是一个socket可以被多个poller对象监听，提高性能或实现Socket归属线程的迁移
     * @param other 原始的socket对象
     * @return 是否成功
     */
    bool cloneSocket(const Socket &other);

    ////////////设置事件回调////////////

    /**
     * 设置数据接收回调,tcp或udp客户端有效
     * @param cb 回调对象
     */
    void setOnRead(onReadCB cb);

    /**
     * 设置异常事件(包括eof等)回调
     * @param cb 回调对象
     */
    void setOnErr(onErrCB cb);

    /**
     * 设置tcp监听接收到连接回调
     * @param cb 回调对象
     */
    void setOnAccept(onAcceptCB cb);

    /**
     * 设置socket写缓存清空事件回调
     * 通过该回调可以实现发送流控
     * @param cb 回调对象
     */
    void setOnFlush(onFlush cb);

    /**
     * 设置accept时，socket构造事件回调
     * @param cb 回调
     */
    void setOnBeforeAccept(onCreateSocket cb);

    /**
     * 设置发送buffer结果回调
     * @param cb 回调
     */
    void setOnSendResult(onSendResult cb);

    ////////////发送数据相关接口////////////

    /**
     * 发送数据指针
     * @param buf 数据指针
     * @param size 数据长度
     * @param addr 目标地址
     * @param addr_len 目标地址长度
     * @param try_flush 是否尝试写socket
     * @return -1代表失败(socket无效)，0代表数据长度为0，否则返回数据长度
     */
    ssize_t send(const char *buf, size_t size = 0, struct sockaddr *addr = nullptr, socklen_t addr_len = 0,
                 bool try_flush = true);

    /**
     * 发送string
     */
    ssize_t send(std::string buf, struct sockaddr *addr = nullptr, socklen_t addr_len = 0, bool try_flush = true);

    /**
     * 发送Buffer对象，Socket对象发送数据的统一出口
     * socket对象发送数据的统一出口
     */
    ssize_t send(ABuffer::Ptr buf, struct sockaddr *addr = nullptr, socklen_t addr_len = 0, bool try_flush = true);

    /**
     * 尝试将所有数据写socket
     * @return -1代表失败(socket无效或者发送超时)，0代表成功?
     */
    int flushAll();

    /**
     * 关闭socket且触发onErr回调，onErr回调将在poller线程中进行
     * @param err 错误原因
     * @return 是否成功触发onErr回调
     */
    bool emitErr(const SockException &err) noexcept;

    /**
     * 关闭或开启数据接收
     * @param enabled 是否开启
     */
    void enableRecv(bool enabled);

    /**
     * 获取裸文件描述符，请勿进行close操作(因为Socket对象会管理其生命周期)
     * @return 文件描述符
     */
    int rawFD() const;

    /**
     * tcp客户端是否处于连接状态
     * 支持Sock_TCP类型socket
     */
    bool alive() const;

    /**
     * 返回socket类型
     */
    SocketNum::SockType sockType() const;

    /**
     * 设置发送超时主动断开时间;默认10秒
     * @param second 发送超时数据，单位秒
     */
    void setSendTimeOutSecond(uint32_t second);

    /**
     * 套接字是否忙，如果套接字写缓存已满则返回true
     * @return 套接字是否忙
     */
    bool isSocketBusy() const;

    /**
     * 获取poller线程对象
     * @return poller线程对象
     */
    const EventLoop::Ptr &getPoller() const;

    /**
     * 绑定udp 目标地址，后续发送时就不用再单独指定了
     * @param dst_addr 目标地址
     * @param addr_len 目标地址长度
     * @param soft_bind 是否软绑定，软绑定时不调用udp connect接口，只保存目标地址信息，发送时再传递到sendto函数
     * @return 是否成功
     */
    bool bindPeerAddr(const struct sockaddr *dst_addr, socklen_t addr_len = 0, bool soft_bind = false);

    /**
     * 设置发送flags
     * @param flags 发送的flag
     */
    void setSendFlags(int flags = SOCKET_DEFAULE_FLAGS);

    /**
     * 关闭套接字
     * @param close_fd 是否关闭fd还是只移除io事件监听
     */
    void closeSock(bool close_fd = true);

    /**
     * 获取发送缓存包个数(不是字节数)
     */
    size_t getSendBufferCount();

    /**
     * 获取上次socket发送缓存清空至今的毫秒数,单位毫秒
     */
    uint64_t elapsedTimeAfterFlushed();

    /**
     * 获取接收速率，单位bytes/s
     */
    int getRecvSpeed();

    /**
     * 获取发送速率，单位bytes/s
     */
    int getSendSpeed();


  protected:
    IPEndPoint *m_ipEndpoint;

  private:
    SocketFD::Ptr cloneSockFD(const Socket &other);

    SocketFD::Ptr makeSock(int sock, SocketNum::SockType type);

    void setSock(SocketFD::Ptr fd);

    int onAccept(int sock, int event) noexcept;

    ssize_t onRead(int sock, SocketNum::SockType type, const BufferRaw::Ptr &buffer) noexcept;

    void onWriteAble(int sock, SocketNum::SockType type);

    void onConnected(int sock, const onErrCB &cb);

    void onFlushed();

    void startWriteAbleEvent(int sock);

    void stopWriteAbleEvent(int sock);

    bool flushData(int sock, SocketNum::SockType type, bool poller_thread);

    bool attachEvent(int sock, SocketNum::SockType type);

    ssize_t send_l(ABuffer::Ptr buf, bool is_buf_sock, bool try_flush = true);

    void connect_l(const std::string &url, uint16_t port, const onErrCB &con_cb_in, float timeout_sec,
                   const std::string &local_ip, uint16_t local_port);

    bool fromSock_l(SocketFD::Ptr sock);

  private:
    //send socket时的flag
    int _sock_flags;
    //最大发送缓存，单位毫秒，距上次发送缓存清空时间不能超过该参数
    uint32_t _max_send_buffer_ms = SEND_TIME_OUT_SEC * 1000;
    //控制是否接收监听socket可读事件，关闭后可用于流量控制
    std::atomic<bool> _enable_recv{true};
    //标记该socket是否可写，socket写缓存满了就不可写
    std::atomic<bool> _sendable{true};
    //是否已经触发err回调了
    bool _err_emit = false;
    //是否启用网速统计
    bool _enable_speed = false;
    // udp发送目标地址
    std::shared_ptr<struct sockaddr_storage> _udp_send_dst;

    //接收速率统计
    BytesSpeed _recv_speed;
    //发送速率统计
    BytesSpeed _send_speed;

    //tcp连接超时定时器
    Timer::Ptr _con_timer;
    //tcp连接结果回调对象
    std::shared_ptr<std::function<void(int)> > _async_con_cb;

    //记录上次发送缓存(包括socket写缓存、应用层缓存)清空的计时器
    Ticker _send_flush_ticker;
    //socket fd的抽象类
    SocketFD::Ptr _sock_fd;
    //本socket绑定的poller线程，事件触发于此线程
    EventLoop::Ptr _poller;
    //跨线程访问_sock_fd时需要上锁
    mutable MutexWrapper<std::recursive_mutex> _mtx_sock_fd;

    //socket异常事件(比如说断开)
    onErrCB _on_err;
    //收到数据事件
    onReadCB _on_read;
    //socket缓存清空事件(可用于发送流速控制)
    onFlush _on_flush;
    //tcp监听收到accept请求事件
    onAcceptCB _on_accept;
    //tcp监听收到accept请求，自定义创建peer Socket事件(可以控制子Socket绑定到其他poller线程)
    onCreateSocket _on_before_accept;
    //设置上述回调函数的锁
    MutexWrapper<std::recursive_mutex> _mtx_event;

    //一级发送缓存, socket可写时，会把一级缓存批量送入到二级缓存
    List<std::pair<ABuffer::Ptr, bool> > _send_buf_waiting;
    //一级发送缓存锁
    MutexWrapper<std::recursive_mutex> _mtx_send_buf_waiting;
    //二级发送缓存, socket可写时，会把二级缓存批量写入到socket
    List<BufferList::Ptr> _send_buf_sending;
    //二级发送缓存锁
    MutexWrapper<std::recursive_mutex> _mtx_send_buf_sending;
    //发送buffer结果回调
    BufferList::SendResult _send_result;
    //对象个数统计
    ObjectStatistic<Socket> _statistic;

    //链接缓存地址,防止tcp reset 导致无法获取对端的地址
    struct sockaddr_storage _local_addr;
    struct sockaddr_storage _peer_addr;
  };

RD_NAMESPACE_END

#endif //RENDU_SOCKET_H
